<!--
 * @name: 
 * @Author: JiaYing
 * @LastEditors: JiaYing
 * @Date: 2022-08-23 16:50:19
 * @LastEditTime: 2022-08-23 18:49:11
 * @Description: 
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>闭包的使用常见场景</title>
  </head>
  <body>
    <span class="span">1</span>
    <div id="box">"===="</div>
  </body>
</html>

<script>
  // 私有变量
  const count = (() => {
    let value = 0;
    return function (step = 1) {
      step = isNaN(+step) ? 1 : step;
      value += step;
      return value;
    };
  })();
  console.log(count());
  console.log(count("a"));
  console.log(count(null));
  console.log(count(10));

  for (var i = 0; i < 10; i++) {
    (function (value) {
      setTimeout(() => {
        console.log("闭包变量 => " + value, "全局变量 =>" + window.i);
      });
    })(i);
  }

  // 私有属性
  function User(option) {
    option = Object.assign({}, option);
    this.name = option.name || null;
    var idNumber = option.idNumber || null;
    this.getIdNumber = function () {
      return idNumber;
    };
  }
  const user = new User({ name: "tony", idNumber: "123" });
  console.log(user);

  // 模块，私有作用域，模块内未对外导出的函数或变量着无法反问
  const $ = (function () {
    const nodes = {};
    function stash(rule) {
      const node = document.querySelector(rule);
      if (node !== null) {
        nodes[rule] = node;
      }
      return {
        key: rule,
        stash,
        find,
      };
    }
    function append(key) {
      const node = key ? nodes[key] : this.key ? nodes[this.key] : null;
      if (node === null) return false;
      this.node.append(node);
      delete nodes[key || this.key];
    }
    function find(rule) {
      const node = document.querySelector(rule);
      return {
        key: this.key,
        node,
        append,
      };
    }
    return {
      stash,
      find,
    };
  })();

  $.stash(".span").find("#box").append();
  $.stash(".span");
  $.find("body").append(".span");

  // 缓存实例
  const createCache = function () {
    const data = {};
    const timers = {};
    const createClearTask = function (key, time) {
      if (time in timers) {
        clearTimeout(timers[key]);
      }
      if (time === 0) {
        delete data[key];
        return;
      }
      timers[key] = setTimeout(() => {
        delete data[key];
      }, time);
      return timers[key];
    };
    return function (key, value, time) {
      if (key === undefined) throw new Error("key is undefined");
      if (value === undefined && time === undefined) return data[key];
      data[key] = value;
      if (typeof time === "number") createClearTask(key, time);
      return value;
    };
  };

  const cache = createCache();
  console.log("b", cache("b", 1, 1000));
  console.log("b", cache("b"));
  console.log("b", cache("b", undefined, 0));
  console.log("b", cache("b"));
  setTimeout(() => {
    console.log("b", cache("b"));
  }, 500);

  // 上级作用域
  function father() {
    var name = "tony";
    return function () {
      console.log(name);
    };
  }
  function mother(fn) {
    var name = "jenny";
    fn(); // tony
    eval("1, " + fn)(); // jennt
  }
  mother(father());
</script>
